import sys
sys.path.append("//../interpreter/")
from functionBinding import functionBinding
from functionDef import functionDef
from application import application
from Return import Return
from builtin import *
from varRef import varRef
from jsobject import *
from interpreter import interpreter
from endvals import *
from objectOps import *
from sequence import *
from conditionals import *
from sequence import *
from varBinding import *
from varMut import *
from customExceptions import *

%%

parser Footle:
   ignore: r"\s+"
   token IF: "if"
   token ELSE: "else"
   token VAR: "var"
   token RET: "return"
   token WHILE: "while"
   token FUN: "function"
   token TRUE: "true"
   token FALSE: "false"
   token NEW: "new"
   token ID: "[a-zA-Z][a-zA-Z0-9]*"
   token NUM: "[0-9]+"
   token FLOAT:r"\.[0-9]+"
   token DOT: r"\."
   token TIMES: r"\*"
   token EQUALS: "="
   token SEMI: ";"
   token NOT: "!"
   token RPAREN: r"\("
   token LPAREN: r"\)"
   token RBRACKET: "}"
   token LBRACKET: "{"
   token STRING: r"\"\.\""
   
   rule stmt:     expr {{obj = expr}} 
                                ( "." ID EQUALS expr {{value = expr}} SEMI {{return fieldMutation(obj, stringval(ID), value) }}
                                  | EQUALS  expr {{value = expr}} SEMI {{ return VarMut(expr, value) }}
                                  | SEMI {{return obj}}
                                )
                     | expr {{ return expr}}
                     | VAR ID EQUALS  expr {{value = expr}} SEMI stmt {{rest = stmt}} {{ return VarBinding(stringval(ID), value, rest) }}
                     | RET expr SEMI {{return Return(expr)}}
                     | IF LPAREN expr {{guard = expr}} RPAREN RBRACKET {{thenlst = []}} {{elselst = []}}
                                                                           ( stmt  {{thenlst.append(stmt)}}
                                                                           )*      LBRACKET  
                                                           [ELSE RBRACKET
                                                           (stmt {{elselst.append(stmt)}}
                                                           )*
                                                           LBRACKET
                                                           ]
                                                           {{return ifthen(guard, sequence(thenlst), sequence(elselst))}}
                     | WHILE LPAREN expr {{guard = expr}} RPAREN RBRACKET {{stmtlst = []}}
                                                                                 (stmt {{stmtlst.append(stmt)}})*
                                                                                 LBRACKET
                                                                                 {{return whileloop(guard, sequence(stmtlst))}}
                     | {{flist = []}} ( FUN ID {{name = ID}} LPAREN {{paramlist = []}} 
                                                   (ID {{paramlist.append(stringval(ID))}}
                                                   )*
                                                 RPAREN LBRACKET {{stmtlst = []}}
                                                 (stmt {{stmtlst.append(stmt)}}
                                                 )* RBRACKET  {{flist.append(functionDef(stringval(name), paramlist, stmtlst))}}
                                       )* stmt {{rest =stmt}} {{return functionBinding(flist, rest)}}
                                                 
   rule expr:   NUM ["." FLOAT {{return flp(float(NUM+"."+FLOAT))}}] {{return integer(int(NUM))}}
                  |  TRUE {{return boolean(True)}}
                  |  FALSE {{return boolean(False)}}
                  |  ID ( LPAREN arglist RPAREN {{return application(ID, arglist)}}
                           | {{return varRef(stringval(ID))}}
                          )
                  |  STRING {{return stringval(STRING)}} # make this work somehow
                  |  LPAREN expr RPAREN  
                                          ( LPAREN arglist RPAREN {{return application(expr, arglist)}}
                                            |{{return expr}}
                                           )
                  |  NEW ID LPAREN arglist RPAREN {{new(varRef(stringval(ID)), arglist)}}
                  |  NOT expr {{return application(strinval("not")[expr]) }}
                  |  expr {{lexp = expr}}
                                         ("." ID 
                                                  ( LPAREN arglist RPAREN {{return methodCall(lexp, stringval(ID), arglist)}}
                                                    | {{return fieldLookup(expr, stringval(ID))}})
                                         | "*" expr {{rexp = expr}} {{return application("*", [lexp, rexp])}}
                                         | "+" expr {{rexp = expr}} {{return application("+", [lexp, rexp])}}
                                         | "-" expr {{rexp = expr}} {{return application("-", [lexp, rexp])}}
                                         | "/" expr {{rexp = expr}} {{return application("/", [lexp, rexp])}}
                                         | ">" expr {{rexp = expr}} {{return application(">", [lexp, rexp])}}
                                         | ">=" expr {{rexp = expr}} {{return application(">=", [lexp, rexp])}}
                                         | "<" expr {{rexp = expr}} {{return application("<", [lexp, rexp])}}
                                         | "<=" expr {{rexp = expr}} {{return application("<=", [lexp, rexp])}}
                                         | "&&" expr {{rexp = expr}} {{return application("&&", [lexp, rexp])}}
                                         | "||" expr {{rexp = expr}} {{return application("||", [lexp, rexp])}}
                                         | "==" expr {{rexp = expr}} {{return application("==", [lexp, rexp])}}
                                         )
                  
   rule arglist: {{arglist = []}} (expr {{arglist.append(expr) }})* {{return arglist}}
